package com.pcbly.web.components.license;

import java.io.Serializable;
import java.io.UnsupportedEncodingException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.dom4j.Document;
import org.dom4j.DocumentFactory;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;

public class LicenseData implements Serializable {

	/**
	 * 
	 */
	private static final long serialVersionUID = -6518982132391611276L;
	private static final Log logger = LogFactory.getLog(LicenseData.class);

	private Date createDate;// 创建日期

	private Date endDate;// 结束日期

	private Client client;// 客户

	private Version version;// 版本

	private int maxNumber;// 最大人数

	private String macNumber;// 机器网卡编码

	private String type;// 评估或正式

	private DateFormat dateFormat;// 日期格式

	private String edition;// 标准版、大众版、企业版

	private String signature;// 数字签名

	private long id;

	private String name;

	private Map<String, String> properties;

	public LicenseData() {
		properties = new HashMap<String, String>();
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public Map<String, String> getProperties() {
		return properties;
	}

	public void setProperties(Map<String, String> properties) {
		this.properties = properties;
	}

	public long getId() {
		return id;
	}

	public void setId(long id) {
		this.id = id;
	}

	public Client getClient() {
		return client;
	}

	public void setClient(Client client) {
		this.client = client;
	}

	public String getEdition() {
		if (edition == null) {
			edition = "大众版";
		}
		return edition;
	}

	public void setEdition(String edition) {
		this.edition = edition;
	}

	public String getSignature() {
		return signature;
	}

	public void setSignature(String signature) {
		this.signature = signature;
	}

	public Date getCreateDate() {
		return createDate;
	}

	public void setCreateDate(Date createDate) {
		this.createDate = createDate;
	}

	public Date getEndDate() {
		return endDate;
	}

	public void setEndDate(Date endDate) {
		this.endDate = endDate;
	}

	public Version getVersion() {
		return version;
	}

	public void setVersion(Version version) {
		this.version = version;
	}

	public int getMaxNumber() {
		if (maxNumber < 1) {
			maxNumber = 10;
		}
		return maxNumber;
	}

	public void setMaxNumber(int maxNumber) {
		this.maxNumber = maxNumber;
	}

	public String getMacNumber() {
		return macNumber;
	}

	public void setMacNumber(String mac) {
		this.macNumber = mac;
	}

	public String getType() {
		return type;
	}

	public void setType(String type) {
		this.type = type;
	}

	public DateFormat getDateFormat() {
		return dateFormat;
	}

	public void setDateFormat(DateFormat dateFormat) {
		this.dateFormat = dateFormat;
	}

	@SuppressWarnings("unchecked")
	public LicenseData fromXML(String xml) throws Exception {

		LicenseData l = new LicenseData();
		Document d = DocumentHelper.parseText(xml);
		Element root = d.getRootElement();
		String maxNumber = root.attributeValue("maxNumber");
		if (maxNumber == null)
			throw new LicenseException("License must contain an maxNumber.");
		l.setMaxNumber(Integer.parseInt(maxNumber));
		String macNumber = root.attributeValue("macNumber");
		if (macNumber == null)
			throw new LicenseException("License must contain an mac Number.");
		l.setMacNumber(macNumber);

		String id = root.attributeValue("id");
		if (id == null)
			throw new LicenseException("License must contain an id.");
		l.setId(Long.parseLong(id));
		String name0 = root.attributeValue("name");
		if (name0 == null)
			throw new LicenseException("License must contain a name.");
		l.setName(name0);
		String edition = root.attributeValue("edition");
		if (edition != null)
			l.setEdition(edition);
		String dateString = root.attributeValue("createDate");
		if (dateString == null)
			throw new LicenseException("License must contain a creation date.");
		try {
			Date date = parseDate(dateString);
			l.setCreateDate(date);
		} catch (Exception e) {
			throw new LicenseException("License creationDate is invalid.");
		}
		dateString = root.attributeValue("endDate");
		if (dateString != null) {
			Date date = parseDate(dateString);
			l.setEndDate(date);
		}

		String license = root.attributeValue("version");
		if (license == null)
			throw new LicenseException("License must contain a version.");
		l.setVersion(Version.parseVersion(license));
		try {
			l.setType(root.attributeValue("type"));
		} catch (IllegalArgumentException e) {
			throw new LicenseException("License must contain a valid type.");
		}
		Element clientElement = root.element("client");
		Client client = new Client();
		client.setName(clientElement.attributeValue("name"));
		client.setCompany(clientElement.attributeValue("company"));
		l.setClient(client);

		Map<String, String> properties = new HashMap<String, String>();
		String name;
		String value;
		for (Iterator<Element> it = root.elements("property").iterator(); it
				.hasNext(); properties.put(name, value)) {
			Element e = it.next();
			name = e.attributeValue("name");
			value = e.getTextTrim();
		}

		l.setProperties(properties);
		Element sig = root.element("signature");
		l.setSignature(sig.getTextTrim());
		return l;
	}

	public String toXML() {
		DocumentFactory factory = DocumentFactory.getInstance();
		Document document = factory.createDocument();
		Element root = document.addElement("license");

		root.addAttribute("id", String.valueOf(getId()));
		if (name != null)
			root.addAttribute("name", getName());
		if (edition != null)
			root.addAttribute("edition", getEdition());
		root.addAttribute("createDate", formatDate(getCreateDate()));
		if (endDate != null) {
			root.addAttribute("endDate", formatDate(getEndDate()));
		}
		root.addAttribute("maxNumber", String.valueOf(getMaxNumber()));
		root.addAttribute("macNumber", getMacNumber());
		root.addAttribute("version", version.getVersionString());
		if (type != null)
			root.addAttribute("type", getType());
		if (signature != null)
			root.addAttribute("signature", getSignature());
		if (client != null) {
			Element clientElement = root.addElement("client");
			if (client.getName() != null)
				clientElement.addAttribute("name", getClient().getName());
			if (client.getCompany() != null)
				clientElement.addAttribute("company", getClient().getCompany());
		}
		if (properties != null) {
			Map.Entry<String, String> entry;
			Element prop;
			for (Iterator<Map.Entry<String, String>> it = getProperties()
					.entrySet().iterator(); it.hasNext(); prop.setText(entry
					.getValue())) {
				entry = it.next();
				prop = root.addElement("property");
				prop.addAttribute("name", entry.getKey());
			}
		}

		return document.asXML();
	}

	public Date parseDate(String date) throws Exception {
		if (dateFormat == null) {
			dateFormat = new SimpleDateFormat("yyyy-MM-dd");
		}
		return dateFormat.parse(date);
	}

	public String formatDate(Date date) {
		if (dateFormat == null) {
			dateFormat = new SimpleDateFormat("yyyy-MM-dd");
		}
		return dateFormat.format(date);
	}

	public byte[] getFingerprint() {
		StringBuffer buf = new StringBuffer(100);
		try {
			buf.append(id);
			buf.append(name);
			buf.append(version);
			buf.append(dateFormat.format(createDate));
			buf.append(type);
			String key;
			for (Iterator<String> i$ = properties.keySet().iterator(); i$
					.hasNext(); buf.append((String) properties.get(key))) {
				key = i$.next();
				buf.append(key);
			}

			if (client != null) {
				buf.append(client.getCompany());
				buf.append(client.getName());
				buf.append(client.getUrl());
			}
			return buf.toString().getBytes("utf-8");
		} catch (UnsupportedEncodingException ue) {
			logger.error(ue.getMessage(), ue);
			return buf.toString().getBytes();
		}
	}

	@Override
	public String toString() {
		return "LicenseData [client=" + client + ", createDate=" + createDate
				+ ", dateFormat=" + dateFormat + ", edition=" + edition
				+ ", endDate=" + endDate + ", id=" + id + ", macNumber="
				+ macNumber + ", maxNumber=" + maxNumber + ", name=" + name
				+ ", properties=" + properties + ", signature=" + signature
				+ ", type=" + type + ", version=" + version + "]";
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ((client == null) ? 0 : client.hashCode());
		result = prime * result
				+ ((createDate == null) ? 0 : createDate.hashCode());
		result = prime * result
				+ ((dateFormat == null) ? 0 : dateFormat.hashCode());
		result = prime * result + ((edition == null) ? 0 : edition.hashCode());
		result = prime * result + ((endDate == null) ? 0 : endDate.hashCode());
		result = prime * result + (int) (id ^ (id >>> 32));
		result = prime * result
				+ ((macNumber == null) ? 0 : macNumber.hashCode());
		result = prime * result + maxNumber;
		result = prime * result + ((name == null) ? 0 : name.hashCode());
		result = prime * result
				+ ((properties == null) ? 0 : properties.hashCode());
		result = prime * result
				+ ((signature == null) ? 0 : signature.hashCode());
		result = prime * result + ((type == null) ? 0 : type.hashCode());
		result = prime * result + ((version == null) ? 0 : version.hashCode());
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		LicenseData other = (LicenseData) obj;
		if (client == null) {
			if (other.client != null)
				return false;
		} else if (!client.equals(other.client))
			return false;
		if (createDate == null) {
			if (other.createDate != null)
				return false;
		} else if (!createDate.equals(other.createDate))
			return false;
		if (dateFormat == null) {
			if (other.dateFormat != null)
				return false;
		} else if (!dateFormat.equals(other.dateFormat))
			return false;
		if (edition == null) {
			if (other.edition != null)
				return false;
		} else if (!edition.equals(other.edition))
			return false;
		if (endDate == null) {
			if (other.endDate != null)
				return false;
		} else if (!endDate.equals(other.endDate))
			return false;
		if (id != other.id)
			return false;
		if (macNumber == null) {
			if (other.macNumber != null)
				return false;
		} else if (!macNumber.equals(other.macNumber))
			return false;
		if (maxNumber != other.maxNumber)
			return false;
		if (name == null) {
			if (other.name != null)
				return false;
		} else if (!name.equals(other.name))
			return false;
		if (properties == null) {
			if (other.properties != null)
				return false;
		} else if (!properties.equals(other.properties))
			return false;
		if (signature == null) {
			if (other.signature != null)
				return false;
		} else if (!signature.equals(other.signature))
			return false;
		if (type == null) {
			if (other.type != null)
				return false;
		} else if (!type.equals(other.type))
			return false;
		if (version == null) {
			if (other.version != null)
				return false;
		} else if (!version.equals(other.version))
			return false;
		return true;
	}

}
